/*
 * Formula Parser
 * @Version: revised version for ABSL
 * @Revised by Hao Ji
 */

package parser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.Hashtable;

public class ParsedUnit {
	private static final long serialVersionUID = 1L;
	protected LinkedList<String> code;
	protected Hashtable<String,String> parsed;
	private int codeLine;

	public ParsedUnit(){
		code=new LinkedList<String>();
	}

	public int getCodeline(){
		return codeLine;
	}
	public void setCodeline(int line){
		this.codeLine=line;
	}
	
//	public int size(){
//		return code.size();
//	}
	public void add(String line){
		parsed=null;
		code.add(line);
	}
	public String get(int index){
		if(code==null) return null;
		return code.get(index);
	}
	
	public ArrayList<String> getKeys(){
//		parse();
		if(parsed!=null && !parsed.isEmpty()){
			ArrayList<String> list=Collections.list(parsed.keys());
			Collections.sort(list);
			return list;
		}else{
			return null;
		}
	}
	public String get(String key){
		if(parsed==null) return null;
		return parsed.get(key);
	}
	public void set(String key,String value){
		if(parsed!=null && value!=null)
			parsed.put(key, value);
	}

	public String toString(){
		if(get(Parser.SIMULATION_UNIT_DOC)!=null) return get(Parser.SIMULATION_UNIT_NATURE)+" "+get(Parser.SIMULATION_UNIT_NAME)+" //"+get(Parser.SIMULATION_UNIT_DOC);
		return get(Parser.SIMULATION_UNIT_NATURE)+" "+get(Parser.SIMULATION_UNIT_NAME);
	}

	protected void parse() throws ParseException{
		parsed=new Hashtable<String,String>();
		String line=get(0);
		String name=line.substring(line.indexOf(' ')+1);
		set(Parser.SIMULATION_UNIT_NAME, name);
		
		String nature=null;
		
		if(line.startsWith(Parser.SIMULATION_UNIT_NATURE_AUX))
			nature=Parser.SIMULATION_UNIT_NATURE_AUX;
		if(line.startsWith(Parser.SIMULATION_UNIT_NATURE_CONST))
			nature=Parser.SIMULATION_UNIT_NATURE_CONST;
		if(line.startsWith(Parser.SIMULATION_UNIT_NATURE_LEVEL))
			nature=Parser.SIMULATION_UNIT_NATURE_LEVEL;
		if(line.startsWith(Parser.SIMULATION_UNIT_NATURE_UNIT))
			nature=Parser.SIMULATION_UNIT_NATURE_UNIT;

		set(Parser.SIMULATION_UNIT_NATURE, nature);
		
		// Unit fertig geparst
		if(nature==Parser.SIMULATION_UNIT_NATURE_UNIT)
			return;


		
		String unit=null;
		String init=null;
		String def=null;
		String levelin=null;
		String levelout=null;
		String doc=null;
		
		for (int i=1;i<code.size();i++){
			line=get(i);
			if(doc!=null && !line.startsWith("note ")){
				doc+="//"+line;
			}
			else if(line.indexOf(' ')==-1){
				if(line.matches(Parser.SIMULATION_UNIT_INTEGRATION_ZEROORDER))
					set(Parser.SIMULATION_UNIT_INTEGRATION, Parser.SIMULATION_UNIT_INTEGRATION_ZEROORDER);
				else if(line.matches(Parser.SIMULATION_UNIT_INTEGRATION_FIRSTORDER))
					set(Parser.SIMULATION_UNIT_INTEGRATION, Parser.SIMULATION_UNIT_INTEGRATION_FIRSTORDER);
				else if(line.matches(Parser.SIMULATION_UNIT_IMMEDIATE))
					set(Parser.SIMULATION_UNIT_IMMEDIATE,"true");
//					throw new ParseException("Immediates werden (noch) nicht untersttzt");
				else if(line.matches(Parser.SIMULATION_UNIT_PERMANENT))
					set(Parser.SIMULATION_UNIT_PERMANENT,"true");
				else if(line.matches(Parser.SIMULATION_UNIT_LEVEL_RESERVOIR))
					set(Parser.SIMULATION_UNIT_LEVEL_RESERVOIR, "true");
				else if(def!=null){
					def+=line;
				}
			}
			else if(line.startsWith("doc ")){
				doc=line.substring(4);
			}
			else if(line.startsWith("def ")){
				def=line.substring(4);
			}
			else{
				String startwith=line.substring(0,line.indexOf(' '));
				line=line.substring(line.indexOf(' ')+1);
				
				if(startwith.matches(Parser.SIMULATION_UNIT_DIM))
					set(Parser.SIMULATION_UNIT_DIM,line.substring(line.indexOf("..")+2));
				else if(startwith.matches(Parser.SIMULATION_UNIT_TYPE))
					set(Parser.SIMULATION_UNIT_TYPE,line);
				else if(startwith.matches(Parser.SIMULATION_UNIT_UNIT))
					unit=line;
				
				else if(startwith.matches(Parser.SIMULATION_UNIT_INIT))
					init=line;

				else if(startwith.matches(Parser.SIMULATION_UNIT_LEVEL_IN)){
					line=line.replaceAll("def ","").replaceAll("\\s","");
					if(line.charAt(0)=='{' && line.charAt(line.length()-1)=='}')
						line=line.substring(1,line.length()-1);
					line="INTEGRATION("+line+")";
					levelin=(levelin==null)?line:levelin+"+"+line;
					set(Parser.SIMULATION_UNIT_LEVEL_IN,levelin);
				}
				else if(startwith.matches(Parser.SIMULATION_UNIT_LEVEL_OUT)){
					line=line.replaceAll("def ","").replaceAll("\\s","");
					if(line.charAt(0)=='{' && line.charAt(line.length()-1)=='}')
						line=line.substring(1,line.length()-1);
					line="INTEGRATION("+line+")";
					levelout=(levelout==null)?line:levelout+"+"+line;
					set(Parser.SIMULATION_UNIT_LEVEL_OUT,levelout);					
				}

				else if(startwith.matches(Parser.SIMULATION_UNIT_NOTE))
					set(Parser.SIMULATION_UNIT_NOTE,line);
				
				else{
					String error="Unbekannter Typ: "+startwith+" "+codeLine;
					System.err.println(error);
					throw new ParseException(error);
				}				
			}
		}

		if(init!=null)
			init=init.replaceAll(" ", "").replaceAll("TIMESTEP", "TIMESTEP()");
		if(def!=null)
			def=def.replaceAll(" ", "").replaceAll("TIMESTEP", "TIMESTEP()");
		

		String type=get(Parser.SIMULATION_UNIT_TYPE);
		if("Real".equals(type)) type="1";
		if("Integer".equals(type)) type="1";
		if("Logical".equals(type)) type="bool";
		if(get(Parser.SIMULATION_UNIT_DIM)!=null)
			type+="[]";
		set(Parser.SIMULATION_UNIT_TYPE,type);
		set(Parser.SIMULATION_UNIT_DIM,null);
		
		if(nature==Parser.SIMULATION_UNIT_NATURE_LEVEL){
			//Parser.SIMULATION_UNIT_LEVEL_RESERVOIR
			def=name;
			if(levelin!=null)
				def=def+"+("+levelin+")";
			if(levelout!=null)
				def=def+"-("+levelout+")";
		}

		set(Parser.SIMULATION_UNIT_UNIT, unit);
		set(Parser.SIMULATION_UNIT_INIT, init);
		set(Parser.SIMULATION_UNIT_DEF, def);
		set(Parser.SIMULATION_UNIT_DOC, doc);
	}
}